package com.zhome.gateway.locator;

import com.zhome.gateway.dto.ZhomeRouteDto;
import com.zhome.gateway.repository.entity.BlackListInfoEntity;
import com.zhome.gateway.repository.entity.ServerInfoEntity;
import com.zhome.gateway.repository.entity.WhiteListInfoEntity;
import com.zhome.gateway.service.BlackListInfoService;
import com.zhome.gateway.service.RouteService;
import com.zhome.gateway.service.WhiteListInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.zuul.filters.RefreshableRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 查询路由信息
 * @author cuiyh9
 * @date 2020/5/9
 */
@Slf4j
public class MySqlClientRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {
    /** 提供给zuul框架使用的Route信息 */
    private Map<String, ZuulProperties.ZuulRoute> routeConcurrentHashMap = new ConcurrentHashMap<>();

    /** 自定义Filter业务中使用的信息 */
    private Map<String, ZhomeRouteDto> zhomeRouteDtoConcurrentHashMap = new ConcurrentHashMap<>();

    private Set<String> blackIpSet = new HashSet<>();
    private Set<String> blackUaSet = new HashSet<>();
    private Set<String> blackTokenSet = new HashSet<>();



    private Map<String, Set<String>> whiteMap = new HashMap<>();


    @Autowired
    private RouteService routeInfoService;

    @Autowired
    private BlackListInfoService blackListInfoService;

    @Autowired
    private WhiteListInfoService whiteListInfoService;

    public MySqlClientRouteLocator(String servletPath, ZuulProperties properties) {
        super(servletPath, properties);
    }

    @Override
    protected LinkedHashMap<String, ZuulProperties.ZuulRoute> locateRoutes() {
        Map<String, ZuulProperties.ZuulRoute> superRouteMap =  super.locateRoutes();
        LinkedHashMap<String, ZuulProperties.ZuulRoute> routeMap = new LinkedHashMap<>(superRouteMap);
        routeMap.putAll(routeConcurrentHashMap);
        return routeMap;
    }


    @Override
    public void refresh() {
        List<ServerInfoEntity> serverInfoEntityList = routeInfoService.queryAllServerInfo();
        if (serverInfoEntityList == null || serverInfoEntityList.isEmpty()) {
            return ;
        }

        List<ZhomeRouteDto>  routeInfoEntityList = routeInfoService.queryAllRoute();
        if (routeInfoEntityList == null || routeInfoEntityList.isEmpty()) {
            return ;
        }
        for (ZhomeRouteDto  zhomeRouteDto:  routeInfoEntityList) {
            ZuulProperties.ZuulRoute zuulRoute = buildZuulRoute(zhomeRouteDto);
            routeConcurrentHashMap.put(zuulRoute.getPath(), zuulRoute);
            zhomeRouteDtoConcurrentHashMap.put(trimPath(zhomeRouteDto.getPath()), zhomeRouteDto);
        }

        List<BlackListInfoEntity>  blackListInfoEntityList = blackListInfoService.queryAll();
        if (blackListInfoEntityList != null) {
            blackIpSet = blackListInfoEntityList.stream().filter(b -> "IP".equals(b.getType())).map(BlackListInfoEntity::getValue).collect(Collectors.toSet());
            blackUaSet = blackListInfoEntityList.stream().filter(b -> "UserAgent".equals(b.getType())).map(BlackListInfoEntity::getValue).collect(Collectors.toSet());
            blackTokenSet = blackListInfoEntityList.stream().filter(b -> "Token".equals(b.getType())).map(BlackListInfoEntity::getValue).collect(Collectors.toSet());
        }
        List<WhiteListInfoEntity>  whiteListInfoEntityList = whiteListInfoService.queryAll();
        if (whiteListInfoEntityList != null) {
            whiteMap = whiteListInfoEntityList.stream()
                    .collect(Collectors.groupingBy(WhiteListInfoEntity::getServerName,
                            Collectors.mapping(WhiteListInfoEntity::getIp, Collectors.toSet())));
        }

        doRefresh();
    }

    public ZhomeRouteDto getZhomeRouteDto(String serverName) {
        return zhomeRouteDtoConcurrentHashMap.get(serverName);
    }

    public boolean isBlackIp(String ip) {
        return blackIpSet.contains(ip);
    }

    public boolean isBlackUa(String ua) {
        return blackUaSet.contains(ua);
    }

    public boolean isBlackToken(String token) {
        return blackTokenSet.contains(token);
    }

    public boolean isNeedValidateWhiteIp(String serverName) {
        Set<String> whiteSet = whiteMap.get(serverName);
        if (whiteSet == null || whiteSet.isEmpty()) {
            return false;
        }
        return true;
    }

    public boolean isWhiteIp(String serverName, String ip) {
        Set<String> whiteSet = whiteMap.get(serverName);
        return whiteSet.contains(ip);
    }

    private ZuulProperties.ZuulRoute buildZuulRoute(ZhomeRouteDto  zhomeRouteDto) {
        String location = zhomeRouteDto.getDomain() + "/" +zhomeRouteDto.getPath();
        ZuulProperties.ZuulRoute zuulRoute = new ZuulProperties.ZuulRoute(zhomeRouteDto.getPath() + "/**", location);
        zuulRoute.setServiceId(zhomeRouteDto.getServerName());
        return zuulRoute;
    }

    private String trimPath(String path) {
        if (StringUtils.isEmpty(path)) {
            return "";
        }
        if (path.startsWith("/") && path.length() > 1) {
            return path.substring(1);
        }
        return path;
    }
}
